package erfgame.core.graphics.renderer.render;

import java.awt.RenderingHints;
import java.io.IOException;
import java.util.Map;
import java.util.logging.Logger;

import javax.xml.parsers.DocumentBuilder;
import javax.xml.transform.Templates;
import javax.xml.transform.Transformer;

import org.apache.batik.bridge.BridgeContext;
import org.apache.batik.bridge.DocumentLoader;
import org.apache.batik.bridge.GVTBuilder;
import org.apache.batik.bridge.SVGAnimationEngine;
import org.apache.batik.bridge.UserAgent;
import org.apache.batik.bridge.UserAgentAdapter;
import org.apache.batik.gvt.GraphicsNode;
import org.w3c.dom.svg.SVGDocument;


import erfgame.core.CompassDirection;
import erfgame.core.Pair;
import erfgame.core.entity.Attachable;
import erfgame.core.entity.Entity;
import erfgame.core.entity.Orientable;
import erfgame.core.entity.State;
import erfgame.core.xml.ObjectXMLFactory;
import erfgame.core.xml.XmlUtil;

public class BatikEntityAnimationFactory implements EntityAnimationFactory {
    
    private static final Logger log = Logger.getLogger(BatikEntityAnimationFactory.class.getName());

    public static final String KEY_ORIENTATION = "orientation";
	public static final String KEY_ROTATION_ANGLE = "rotation-angle";
	public static final String KEY_STATE = "state";
	
	private UserAgent userAgent;
	private DocumentLoader loader;
	private GVTBuilder builder;
	
	private Templates templates;
	private DocumentBuilder documentBuilder;
	private ObjectXMLFactory<Entity> xmlFactory;
	private Map<String, Object> globalParameters;
	
	public BatikEntityAnimationFactory(Templates templates, ObjectXMLFactory<Entity> xmlFactory, DocumentBuilder documentBuilder, Map<String, Object> globalParameters) {
		this.templates = templates;
		this.xmlFactory = xmlFactory;
		this.documentBuilder = documentBuilder;
		this.globalParameters = globalParameters;
		
		userAgent = new UserAgentAdapter();
		loader = new DocumentLoader(userAgent);
		builder = new GVTBuilder();
	}
	
	public Animation getAnimation(Entity entity, State state, CompassDirection orientation, double rotation) throws Exception {

		Transformer transformer = templates.newTransformer();
		// transform to SVG
		if( orientation != null ) {
		    transformer.setParameter(KEY_ORIENTATION, orientation.name());
		}
		transformer.setParameter(KEY_ROTATION_ANGLE, rotation);
		if( state != null ) {
		    transformer.setParameter(KEY_STATE, state.getName());
		}
        for( Map.Entry<String, Object> entry : this.globalParameters.entrySet() ) {
            transformer.setParameter(entry.getKey(), entry.getValue());
        }
        final String svgString = XmlUtil.transformToSVGString(documentBuilder, xmlFactory, entity, transformer);
        
        return new Animation() {
            
            public Render getFrame(float progress) {
            	try {
            		SVGDocument svg = XmlUtil.stringToSVG(svgString);
	                BridgeContext ctx = new BridgeContext(userAgent, loader);
	                ctx.setDynamicState(BridgeContext.DYNAMIC);
	                                
	                GraphicsNode rootGN = builder.build(ctx, svg);
	//              BufferedImage image = new BufferedImage(100, 100, BufferedImage.TYPE_INT_ARGB);
	//              Graphics2D graphics = (Graphics2D)image.getGraphics();
	//              rootGN.paint(graphics);
	//              graphics.setColor(Color.red);
	//              graphics.drawRect(0, 0, image.getWidth()-1, image.getHeight()-1);
	//              graphics.dispose();
	//              return new ImageRender(image);
	                SVGAnimationEngine animationEngine = ctx.getAnimationEngine();
	                if( !animationEngine.hasStarted() ) {
	                    animationEngine.start(System.currentTimeMillis());          
	                }
	//                ((SVGOMDocument)svg).getRootElement().setCurrentTime(progress);
	//                animationEngine.setCurrentTime(progress);
	                if( !animationEngine.isPaused() ) {
	                    animationEngine.pause();
	                }
	                animationEngine.setCurrentTime(progress);
	                //ctx.getAnimationEngine().setCurrentTime(progress);
	                rootGN.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
	                rootGN.setRenderingHint(RenderingHints.KEY_STROKE_CONTROL, RenderingHints.VALUE_STROKE_NORMALIZE);
	                rootGN.setRenderingHint(RenderingHints.KEY_ALPHA_INTERPOLATION, RenderingHints.VALUE_ALPHA_INTERPOLATION_QUALITY);
	                rootGN.setRenderingHint(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_QUALITY);
	                return new BatikRender(svg, rootGN, ctx);
            	} catch( IOException ex ) {
            		throw new RuntimeException( "unable to render frame "+progress, ex );
            	}
            }
        };
		// render
	}

	protected CompassDirection getOrientation(Entity entity) {
		CompassDirection result;
		if( entity instanceof Orientable ) {
			result = ((Orientable)entity).getOrientation();
		} else {
			result = null;
		}
		if( result == null ) {
			if( entity instanceof Attachable ) {
				Entity parent = ((Attachable)entity).getParent();
				result = getOrientation(parent);
			}
		}
		return result;
	}
	
	protected double getRotationAngle(Entity entity) {
		return 0;
	}
	
	protected double getLengthMultiplier(Entity entity) {
		return 1;
	}
	
	protected double getBreadthMultiplier(Entity entity) {
	    return 1;
	}
	
	protected Pair<Integer, Integer> getPrimaryColorRange(Entity entity) {
		// TODO material type color factory
		return new Pair<Integer, Integer>(0x000000, 0xFFFFFF);
	}
}
